package home.contaduria.service.impl;

import home.contaduria.dao.ClientDao;
import home.contaduria.dao.ExpenseDao;
import home.contaduria.dao.ExpenseTypeDao;
import home.contaduria.domain.Client;
import home.contaduria.domain.Expense;
import home.contaduria.domain.ExpenseType;
import home.contaduria.service.ExpenseService;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("expenseService")
public class ExpenseServiceImpl implements ExpenseService {
    private static final Logger logger = LoggerFactory.getLogger(ExpenseServiceImpl.class);

    private ExpenseDao expenseDao;
    private ExpenseTypeDao expenseTypeDao;
    private ClientDao clientDao;

    @Autowired
    public ExpenseServiceImpl(ExpenseDao expenseDao, ExpenseTypeDao expenseTypeDao, ClientDao clientDao) {
        this.expenseDao = expenseDao;
        this.expenseTypeDao = expenseTypeDao;
        this.clientDao = clientDao;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createExpense(Expense expense) {
        updateExpenseType(expense);

        Client persistentClient = clientDao.read(expense.getClient().getId());
        expense.setClient(persistentClient);

        logger.info("Creating expense {}", expense);

        expenseDao.create(expense);
    }


    @Override
    @Transactional(readOnly = true)
    public Expense readExpense(Long id) {
        return expenseDao.read(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Expense> listExpenses(Client client) {
        return expenseDao.findExpenses(client);
    }

    @Override
    @Transactional(readOnly = true)
    public List<Expense> listExpenses(Client client, int firstResult, int maxResults) {
        return expenseDao.findExpenses(client, firstResult, maxResults);
    }

    @Override
    @Transactional(readOnly = true)
    public Long countExpensesNumber(Client client) {
        return expenseDao.countExpensesNumber(client);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateExpense(Expense expense) {
        updateExpenseType(expense);
        expenseDao.update(expense);
        logger.info("Updating expense {}", expense);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteExpense(Long id) {
        Expense expense = expenseDao.read(id);
        expenseDao.delete(expense);
        logger.info("Removing expense {}", expense);
    }

    private void updateExpenseType(Expense expense) {
        ExpenseType expenseType = expense.getType();
        logger.info("Updating expense type {}", expenseType);
        ExpenseType existingExpenseType = expenseTypeDao.findExpenseType(expenseType.getName(), expense.getClient());
        if (existingExpenseType != null) {
            logger.info("Use existing expenseType {} in expense", existingExpenseType);
            expenseType = existingExpenseType;
        } else {
            logger.info("Create a new expense type {} for client {}", expenseType.getName(), expense.getClient());
            expenseType.setClient(expense.getClient());
            expenseTypeDao.create(expenseType);
        }
        expense.setType(expenseType);
    }

}
